package vn.edu.saigontech.ncms.web.teacher.report.haftmonth;

import java.text.Collator;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;

import vn.edu.saigontech.ncms.model.enumeration.TeacherType;
import vn.edu.saigontech.ncms.model.info.Offering;
import vn.edu.saigontech.ncms.model.info.Teacher;
import vn.edu.saigontech.ncms.model.teaching.TeachingInterruption;
import vn.edu.saigontech.ncms.service.DayOffService;
import vn.edu.saigontech.ncms.service.OfferingService;
import vn.edu.saigontech.ncms.util.Checker;
import vn.edu.saigontech.ncms.util.DateUtil;
import vn.edu.saigontech.ncms.web.teacher.report.OfferingTeachingDetail;
import vn.edu.saigontech.ncms.web.teacher.report.TeacherTeachingDetail;

public class TeachingClassesHalfMonthReport {

	private LinkedList<Date> range = new LinkedList<Date>();
	LinkedList<TeacherTeachingDetail> teachings = new LinkedList<TeacherTeachingDetail>();
	
	public TeachingClassesHalfMonthReport(Date fromDate, Date toDate) {
		this.range = new LinkedList<Date>(DateUtil.sequence(fromDate, toDate));
		this.init();
	}
	
	public void init() {
		Collection<Offering> midOfferings = OfferingService.INSTANCE.findByMidTestAndDate(this.range.getFirst(), this.range.getLast());
		Collection<Offering> finalOfferings = OfferingService.INSTANCE.findByFinalTestAndDate(this.range.getFirst(), this.range.getLast());
		
		this.getOfferingDetailRow(finalOfferings, true);
		this.getOfferingDetailRow(midOfferings, false);

		addCurrentClassesForTeacher();
		sortByTeacher();
	}
	
	private void addCurrentClassesForTeacher() {
		for (TeacherTeachingDetail each : teachings) {
			TeacherTeachingDetail detail = this.getTeaching(each.getTeacher());
			Collection<Offering> offerings = OfferingService.INSTANCE.findByDateAndTeacher(each.getTeacherId(), this.range.getFirst(), this.range.getLast());
			for (Offering offering : offerings) {
				OfferingTeachingDetail offeringDetail = 
						new OfferingTeachingDetail(offering, offering.getLevel().getHours(), OfferingService.HOURS_PER_SESSION, 1, "", false);
				if (!detail.getDetails().contains(offeringDetail))
					detail.add(offeringDetail);
			}
		}
	}

	private void getOfferingDetailRow(Collection<Offering> offerings, boolean isFinal) {
		
		for(Offering offering : offerings) {
			/* list of dates from the start-date of this OFFERING to mid-term test date */
			List<Date> dates = new ArrayList<Date>();
			try {
				if (offering.isCancel()) dates = DateUtil.sequenceAsList(offering.getStartDate(), offering.getEndDate());					
				else if (isFinal) dates = DateUtil.sequenceAsList(DateUtil.addDay(offering.getMidtermWrittenDate(), 1), offering.getEndDate());
				else dates = DateUtil.sequenceAsList(offering.getStartDate(), offering.getMidtermWrittenDate());
			} catch (Exception ex) {
				System.out.println("The date may be null. Info: " + ex.getMessage());
			}
				
			/* exclude all the date-offs */
			LinkedList<Date> consideredDates = new LinkedList<Date>();
			for(Date date : dates) {
				if(!DayOffService.INSTANCE.exists(date)) {
					consideredDates.add(date);
				}
			}
			
			for(Date date : consideredDates) {
				// included switch and interruption
				Teacher teacher = offering.getTeacher(date);
				TeachingInterruption interruption = offering.getInstructorInterruption(date);
				int status = 0;
				if(Checker.isNotNull(interruption)) {
					status = interruption.getStatus(date);
				}
				if(status != TeachingInterruption.CANCEL_REASON && Checker.isNotNull(teacher)) {
					/* build data for teacher report */
					String fullName = teacher.getFullName();
					TeacherTeachingDetail teacherDetail = this.getTeaching(fullName);
					if(Checker.isNull(teacherDetail)) {
						teacherDetail = new TeacherTeachingDetail(teacher.getId(), teacher.getFirstName(), fullName, TeacherType.INSTRUCTOR, teacher.getNationality());
						teacherDetail.setFirstName(teacher.getFirstName());
						teacherDetail.setLastName(teacher.getLastName());
						teacherDetail.setMidName(teacher.getMidName());
						this.teachings.add(teacherDetail);
					}
					OfferingTeachingDetail offeringDetail = teacherDetail.getDetail(offering);
					if(Checker.isNull(offeringDetail)) {
						offeringDetail = new OfferingTeachingDetail(offering, offering.getLevel().getHours(), OfferingService.HOURS_PER_SESSION, 1, "", true);
						teacherDetail.add(offeringDetail);
					} else {
						offeringDetail.setSessions(offeringDetail.getSessions() + 1);
					}
				}
			}
		}
	}

	private TeacherTeachingDetail getTeaching(String teacher) {
		for(TeacherTeachingDetail each : this.teachings) {
			if(each.getTeacher().equalsIgnoreCase(teacher)) {
				return each;
			}
		}
		return null;
	}
	
	private void sortByTeacher() {
		Collections.sort(this.teachings, new Comparator<TeacherTeachingDetail>() {
			@Override
			public int compare(TeacherTeachingDetail o1, TeacherTeachingDetail o2) {
				Locale[] locales = Collator.getAvailableLocales();
				Locale locale = Locale.getDefault();
				for (int i = 0; i < locales.length; i++) {
					if(locales[i].getLanguage().equals("vi")) {
						locale = locales[i];
						continue;
					}
				}
				Collator collator = Collator.getInstance(locale);
				return collator.compare(o1.getSortName(), o2.getSortName());
			}
		});
	}

	public LinkedList<TeacherTeachingDetail> getTeachings() {
		return teachings;
	}
}